//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include<PowerInc.h>
#include <VirtualDevice.h>
#include <TimeManager.h>
#include <Zenr_api.h>

CVirtualDevice * g_display = NULL;
CVirtualDevice * g_keypad = NULL;
CVirtualDevice * g_minisd = NULL;
CVirtualDevice * g_audio = NULL;
CVirtualDevice * g_camera = NULL;
CVirtualDevice * g_tinycam = NULL;
CVirtualDevice * g_doc = NULL;
CVirtualDevice * g_comm = NULL;
CVirtualDevice * g_bt = NULL;
CVirtualDevice * g_fm = NULL;
CVirtualDevice * g_i2c = NULL;
CVirtualDevice * g_cpu = NULL;

EXTERN UInt32 getisLCDBeenshut();
extern"C" IDeviceDriver *  PoRegisterDevice(wchar_t * Name, IInterface * pObject);
extern Bool32 g_allDevicesDown;
void PoBusPowerHandle(int eType, int nCode, void *pParam);
void Bt_ChangeMode(void * pdevice);

UInt32 g_manualLowTime = 5;
UInt32 g_manualHighTime = 5;
UInt32 g_auto = 20;
static Boolean s_blackWithoutLock = FALSE;

IDeviceDriver * PoRegisterDevice(wchar_t * Name, IInterface * pObject)
{//it's so dirty implemention,change later.
    if (wcscmp(Name, L"device:display0") == 0) {//for lcd
        CVirtualDevice *pidevice = new CVirtualDevice(pObject,
            DevicePowerOn, FALSE, TRUE);//not surport all device.
        DebugPrint("device :display\n");
        g_display=pidevice;
        return pidevice;
    }
    if (wcscmp(Name, L"device:keypad0") == 0) {//for keypad
        CVirtualDevice *pidevice = new CVirtualDevice(pObject, DevicePowerOn);
        //not surport all device.
        DebugPrint("device :keypad\n");
        g_keypad=pidevice;
        pidevice->IgnoreRead = TRUE;
        pidevice->ModeChangeInterval = 5/*s*/;
        pidevice->RestartTimer();//If init power on?
        return pidevice;
    }
//    if (wcscmp(Name, L"device:minisdbus") == 0) {//for minisd
//        CVirtualDevice *pidevice = new CVirtualDevice(pObject, DevicePowerOn);
//        //not surport all device.
//        DebugPrint("device :minisd\n");
//        g_minisd=pidevice;
//        return pidevice;
//    }
    if (wcscmp(Name, L"device:wave0") == 0) {//for audio
        CVirtualDevice *pidevice = new CVirtualDevice(pObject,
            DeviceSuspend, FALSE, TRUE);//not surport all device.
        DebugPrint("device :audio\n");
        g_audio=pidevice;
        return pidevice;
    }
    if (wcscmp(Name, L"device:camera0") == 0) {//for camera
        CVirtualDevice *pidevice = new CVirtualDevice(pObject,
            DeviceSuspend, FALSE, FALSE);//not surport all device.
        DebugPrint("device :camera\n");
        g_camera=pidevice;
        return pidevice;
    }
    if (wcscmp(Name, L"device:tinycam0") == 0) {//for tiny camera
        CVirtualDevice *pidevice=new CVirtualDevice(pObject,DeviceSuspend,FALSE,FALSE);//not surport all device.
        DebugPrint("device :tinycam\n");
        g_tinycam=pidevice;
        return pidevice;
    }
    if (wcscmp(Name, L"device:docstorage0") == 0) {//for doc
        CVirtualDevice *pidevice=new CVirtualDevice(pObject,DevicePowerOn);//not surport all device.
        DebugPrint("device :doc\n");
        AddNotify(EVENT_BUS_POWER,(void *)PoBusPowerHandle);
        g_doc=pidevice;
        return (IDeviceDriver * )pObject;//for bus device,we may not capture call but hook.
        //for bus device,we may not capture call but hook.
    }
    if (wcscmp(Name, L"device:serial1") == 0) {//for FFUART
        CVirtualDevice *pidevice = new CVirtualDevice(pObject, DevicePowerOn,
            FALSE, TRUE);//not surport all device.
        DebugPrint("device :serial1\n");
        g_comm=pidevice;
        return pidevice;
    }
    if (wcscmp(Name, L"device:btpoweron") == 0) {//for BTUART
        CVirtualDevice *pidevice = new CVirtualDevice(pObject, DeviceSuspend,
            FALSE, TRUE);//not surport all device.
        DebugPrint("device :btpoweron\n");
        g_bt=pidevice;
        //pidevice->ModeChangeInterval = 60/*s*/;
        //g_bt->SetChangeModeCallBack(Bt_ChangeMode);
        return pidevice;
    }
    if (wcscmp(Name, L"device:fmradio") == 0) {//for fm
        CVirtualDevice *pidevice=new CVirtualDevice(pObject,DevicePowerOff, FALSE, TRUE);//not surport all device.
        DebugPrint("device :fm\n");
        g_fm=pidevice;
        return pidevice;
    }
    if (wcscmp(Name, L"device:i2cbus") == 0) {//for i2cbus
        CVirtualDevice *pidevice=new CVirtualDevice(pObject,DevicePowerOff);//not surport all device.
        DebugPrint("device :i2c\n");
        g_i2c=pidevice;
        return pidevice;
    }
    if (wcscmp(Name, L"device:power") == 0) {//for cpu
        CVirtualDevice *pidevice = new CVirtualDevice(pObject,
            DevicePowerOn, TRUE, TRUE);//not surport all device.
        pidevice->KeepOn=TRUE;
        DebugPrint("device:cpu\n");
        g_cpu=pidevice;
        return pidevice;
    }

    return (IDeviceDriver *)pObject;
}

Boolean PoGetLcdLockScreen();
void PoSetCpuPowerOn(Boolean PowerOn);
void PoDoMachineSleep(Boolean Sleep);

Boolean bManualLock = TRUE;
static Boolean s_LCDBlack = FALSE;
/*state:
  0x00:   LCD OFF
  0x01:   LCD ON
*/
Boolean IsLcdBlack()
{
    return s_LCDBlack;
}

void SetLCDStateOFF()
{
    s_LCDBlack = TRUE;
}

void SetLCDStateON()
{
    s_LCDBlack = FALSE;
}

ECode NotifyAnimationThreadLDCState(UInt32 state)
{
    EmIsrParameter  param;
    param.nParameter1 = state;
    return EmPostEventByIsr(300, &param);
}

void TurnOffLCDAndTouch()
{
    if (!s_LCDBlack) {
        g_display->ChangeMode(DevicePowerOff);
    }
}

/* nCode:
    0x00:   Only LCD PowerOn
    0x01:   SMS Event
    0x02:   Phone Call Event
    0x10:   Keypad Down
    0x11:   Lock Key down
    0x12:   Off Key down
    0x20:   Touch Down
    0x40:   EarpButton Press
    0x50:   Shortcut key (Volume up/down etc.)
    0x80:   Lock Screen Event
    0x81:   Unlock Screen Event
    0x82:   Auto Lock (black light off)
 */
extern"C" void InputEventHandler(void * pArg)
{
    int nCode = (int)pArg;
//    kprintf("\nInputEvent 0x%x (%d)\n", nCode, PoGetLcdLockScreen());

    if (PoGetLcdLockScreen()) {//Locked
		if (0x82 == nCode) {
            TurnOffLCDAndTouch();
            return;
		}
        g_cpu->UpdateInputLastUse();

        if (0x80 == nCode && s_LCDBlack) return;

        if (!g_display->KeepOn) {
            if (0x82 != nCode) {
                g_display->ChangeMode(DevicePowerOn);
            }
            if (nCode == 2) {//Phone call
                g_display->UpdateInputLastUse();
            } else {
                g_display->ChangeMode(DevicePowerOn);
            	if (DevicePowerOn == g_display->PowerState) {//ManualLock
                	g_display->RestartTimer(g_manualHighTime);
                	g_cpu->RestartTimer(g_manualHighTime + g_manualLowTime);
            	} else {//Auto Lock
            		PowerStopTimer(g_display->hTimer);
            	    g_cpu->RestartTimer(5);
            	}
            }
        }
        else {//Keep on
            g_display->ChangeMode(DevicePowerOn);
        }

        return ;
    }

	if (0x82 == nCode) {
    	//if Auto locked, then turn off the lcd and set g_isSleeped TRUE,
		//look like the machine is sleep,but the machine will real sleep after 5 second.
        TurnOffLCDAndTouch();
		return;
	}

    g_display->ChangeMode(DevicePowerOn);
    if (!g_display->KeepOn) g_display->RestartTimer();
    if (g_cpu && !g_cpu->KeepOn) PoSetCpuPowerOn(TRUE);

    return ;
}

//highttime is LCD normal power time, lowLightTime is LCD low power timer
void PoSetLcdAutoLockTimePolicy(UInt32 byAuto) {
    g_auto = byAuto;
}

void PoSetLcdManualLockTimePolicy (UInt32 byManualLow, UInt32 byManualHigh) {
    g_manualLowTime = byManualLow;
    g_manualHighTime = byManualHigh;
}

//flag= -1000: LCD Off now, -1:LCD KeepOn, 0:LCD Normal, [n]:LCD Interval
void PoEventHandler(void * pArg)
{
    int flag = (int)pArg;
    //cprintf("\nPoEvent %d (%d)\n", flag, PoGetLcdLockScreen());

    if (flag == -1000) {
        g_keypad->RestartTimer(0);//Short
        NotifyByIsr(EVENT_AUTO_SLEEP,1,NULL);
        return ;
    }

    if (flag == -1) {
        g_display->KeepSpecifiedMode((UInt32)DevicePowerOn,TRUE);
    }
    else if (flag == 0) {
        g_display->KeepSpecifiedMode((UInt32)DevicePowerOn,FALSE);
    }
    else {
        int nInterval = (int)flag;
        g_display->KeepSpecifiedMode((UInt32)DevicePowerOn,FALSE);
        g_display->SetChangeModeInterval(nInterval);
    }

    if (PoGetLcdLockScreen() && !g_display->KeepOn) {//Locked
        g_display->RestartTimer(5);
    }

    return ;
}

//nCode ,upper 16bit is device class,and lower 16bits is device no.
void PoBusPowerHandle(int eType, int nCode, void *pParam)
{
    int devclass = nCode>>16;
    //int devno = nCode & 0xffff;

    if(devclass == 1 && g_doc != NULL) {// for doc
        g_doc->ChangeMode(DevicePowerOn);
        if(!g_doc->KeepOn)g_doc->RestartTimer();
    }
    else if (devclass == 2 && g_bt != NULL) {// for bt
        g_bt->ChangeMode(DevicePowerOn);
        if(!g_bt->KeepOn)g_bt->RestartTimer();
    }
//    else if (devclass == 3 && g_i2c != NULL) {// for i2c
//        g_i2c->ChangeMode(DevicePowerOn);
//        if(!g_i2c->KeepOn)g_i2c->RestartTimer();
//    }
}

extern"C" void DM_NotifyInput(int eType, int nCode, void *pParam)
{
    NotifyByIsr(EVENT_POWER,(int)InputEventHandler,(void *)nCode);
}

void ShowDeviceStatus();

void EnterSleepModeCallback(int eType, int nCode, void *pParam)
{
    //ShowDeviceStatus();
    if (g_display) {
        g_display->PowerState = DevicePowerOff;
    }
    if (g_keypad) {
        g_keypad->PowerState = DevicePowerOff;
    }
    if (g_audio) {
        g_audio->PowerState = DevicePowerOff;
    }
    if (g_camera) {
        g_camera->PowerState = DevicePowerOff;
    }
    if (g_tinycam) {
        g_tinycam->PowerState = DevicePowerOff;
    }
    if (g_minisd) {
        g_minisd->PowerState = DevicePowerOff;
    }
    if (g_doc) {
        g_doc->PowerState = DevicePowerOff;
    }
    if (g_comm) {
        (g_comm)->PowerState = DevicePowerOff;
    }
    if (g_bt) {
        g_bt->PowerState = DevicePowerOff;
    }
    if (g_fm) {
        (g_fm)->PowerState = DevicePowerOff;
    }

    //zapi_System->allDevicesShutdown();

	PowerStopTimer(g_cpu->hTimer);//for tmep
	g_allDevicesDown = TRUE;

    DebugPrint("all device power off!\n");
}

unsigned long PoGetLcdPowerMode()
{
    if (NULL == g_display) return 4;
    return g_display->PowerState;
}

unsigned long PoGetLcdPowerPolicy()
{
    if (NULL == g_display) return 4;//always on
    return g_display->KeepOn;
}

void  PoSetLcdPowerOn(Boolean PowerOn)
{
    if (NULL == g_display) return;
    g_display->KeepSpecifiedMode((UInt32)DevicePowerOn,PowerOn);
}

void PoSetKeypadPowerOn(Boolean PowerOn)
{
    if (NULL == g_keypad) return;
    g_keypad->KeepSpecifiedMode((UInt32)DevicePowerOn,PowerOn);
}

void PoSetCameraPowerOn(Boolean PowerOn)
{
    if (NULL == g_camera) return;
    g_camera->KeepSpecifiedMode((UInt32)DevicePowerOn,PowerOn);
}

void PoSetTinyCamPowerOn(Boolean PowerOn)
{
    if (NULL == g_tinycam) return;
    g_tinycam->KeepSpecifiedMode((UInt32)DevicePowerOn,PowerOn);
}

void PoSetCpuPowerOn(Boolean PowerOn)
{
    //kprintf("PoSetCpuPowerOn %x\n", PowerOn);

    if(NULL == g_cpu) return;
    g_cpu->KeepSpecifiedMode((UInt32)DevicePowerOn, PowerOn);
}

void PoSetAudioPowerOn(Boolean PowerOn)
{
    if(NULL == g_audio) return;
    g_audio->KeepOn = PowerOn;
}

void PoSetFMPowerOn(Boolean PowerOn)
{
    if(NULL == g_fm) return;
    g_audio->KeepOn = PowerOn;
}

void PoSetI2CPowerOn(Boolean PowerOn)
{
    if(NULL == g_i2c) return;
    g_i2c->KeepSpecifiedMode((UInt32)DevicePowerOn, PowerOn);
}

void PoDoMachineSleep(Boolean Sleep)
{
    if(PoGetLcdLockScreen()) return ;

    PoSetCpuPowerOn(FALSE);//cpu sleep enabled
    g_cpu->RestartTimer(60);//sleep also after 60s though no lock event.
}

Boolean IsDeviceCanPowerOff()
{
    //if(g_audio == NULL || g_camera == NULL || g_minisd == NULL || g_display == NULL||g_cpu ==NULL||g_doc ==NULL||g_comm ==NULL ||g_bt ==NULL)return true;
    return (//(!g_audio || g_audio->PowerState!=DevicePowerOn)
    (!g_camera || (g_camera->PowerState!=DevicePowerOn))
    &&(!g_tinycam || (g_tinycam->PowerState!=DevicePowerOn))
//    &&(!g_minisd || (g_minisd->PowerState!=DevicePowerOn))
    &&(!g_doc || (g_doc->PowerState!=DevicePowerOn))
    &&(!g_comm || (g_comm->PowerState!=DevicePowerOn))
    &&(!g_bt || (g_bt->PowerState!=DevicePowerOn))
    &&(!g_display || (g_display->PowerState!=DevicePowerOn))
    &&((!g_display || !g_display->KeepOn) && getisLCDBeenshut())
    &&(!g_audio || !g_audio->KeepOn)
    &&(!g_cpu || !g_cpu->KeepOn)
    &&(!g_fm || !g_fm->KeepOn));
}

void PoSetLcdPoweroffInterval(int interval)
{
    if(NULL == g_display) return;
    g_display->SetChangeModeInterval(interval);
}

//flag ==0:suspend bt device,[n]:interval
void PoSetBtPowerPolicy(void * pArg)
{
    if(NULL == g_bt) return;
    int flag = (int)pArg;
    if (flag == 0) {//suspend bt device
        g_bt->ChangeMode(DeviceSuspend);
        PowerStopTimer(g_bt->hTimer);
    }
    else {
        int nInterval = (int)flag;
        g_bt->ChangeMode(DevicePowerOn);
        g_bt->SetChangeModeInterval(nInterval);
    }
}

void PoSetLcdChangeModePorc(TimerCallBackProc proc)
{
    if (NULL == g_display) return;
    g_display->SetChangeModeCallBack(proc);
}

void LCD_ChangeMode(void * pdevice);
TimerCallBackProc PoGetLcdChangeModePorc()
{
    return LCD_ChangeMode;
}

static Int32 LockScreen = FALSE;
static Int32 bDisplayKeepOn = FALSE;
void PoSetLcdLockScreen(Boolean Lock)
{
    LockScreen = Lock;
    if (Lock) {
        bDisplayKeepOn = InterlockedCompareExchange(&g_display->KeepOn, FALSE, TRUE);
        s_blackWithoutLock = FALSE;
        if (bDisplayKeepOn) cprintf("Save display keep on \n");
    }
    else {
        if (bDisplayKeepOn) cprintf("Restore display keep on\n");
        g_display->KeepOn = InterlockedCompareExchange(&bDisplayKeepOn, FALSE, TRUE);
    }
}

Boolean PoGetLcdLockScreen()
{
    return LockScreen;
}

void EnterDeepSleepWithoutLock()
{
    if (!LockScreen) {
        s_blackWithoutLock = TRUE;
        PoSetCpuPowerOn(FALSE);
        g_cpu->UpdateInputLastUse();
    }
}

void ExitDeepSleepWithoutLock()
{
    if (s_blackWithoutLock) {
        s_blackWithoutLock = FALSE;
    }
}

Boolean PoGetLCDBlackWithoutLock()
{
    return s_blackWithoutLock;
}

void PoChangeLcdModeOn()
{
    if (NULL == g_display) return;
    g_display->ChangeMode(DevicePowerOn);
}

void PoSetLcdModeOff()
{
    if (NULL == g_display) return;
    g_display->SetMode(1000);
}

char * PowerStatus(unsigned long mode)
{
    switch (mode) {
        case DevicePowerOff:return "DevicePowerOff";
        case DeviceVeryLowPower:return "DeviceVeryLowPower";
        case DeviceSuspend:return "DeviceSuspend";
        case DeviceLowPower:return "DeviceLowPower";
        case DevicePowerOn:return "DevicePowerOn";
        default:return "Undefined Status";
    }
}

EXTERN void ShowDeviceStatus()
{
    DebugPrint("System Device Power Status Report:\n");
    if(g_cpu)DebugPrint("CPU             %s: %d %d,left %d\n",PowerStatus(g_cpu->PowerState),g_cpu->PowerState, g_cpu->KeepOn, g_cpu->GetLeftInterval());
    if(g_display)DebugPrint("LCD             %s: %d %d,left %d\n",PowerStatus(g_display->PowerState),g_display->PowerState, g_display->KeepOn, g_display->GetLeftInterval());
    if(g_audio)DebugPrint("Audio           %s: %d %d,left %d\n",PowerStatus(g_audio->PowerState),g_audio->PowerState, g_audio->KeepOn, g_audio->GetLeftInterval());
    if(g_minisd)DebugPrint("MiniSD          %s: %d %d,left %d\n",PowerStatus(g_minisd->PowerState),g_minisd->PowerState, g_minisd->KeepOn, g_minisd->GetLeftInterval());
    if(g_keypad)DebugPrint("Keypad          %s: %d %d,left %d\n",PowerStatus(g_keypad->PowerState),g_keypad->PowerState, g_keypad->KeepOn, g_keypad->GetLeftInterval());
    if(g_camera)DebugPrint("Camera          %s: %d %d,left %d\n",PowerStatus(g_camera->PowerState),g_camera->PowerState, g_camera->KeepOn, g_camera->GetLeftInterval());
    if(g_tinycam)DebugPrint("TinyCam         %s: %d %d,left %d\n",PowerStatus(g_tinycam->PowerState),g_tinycam->PowerState, g_tinycam->KeepOn, g_tinycam->GetLeftInterval());
    if(g_doc)DebugPrint("Doc             %s: %d %d,left %d\n",PowerStatus(g_doc->PowerState),g_doc->PowerState, g_doc->KeepOn, g_doc->GetLeftInterval());
    if(g_comm)DebugPrint("Comm            %s: %d %d,left %d\n",PowerStatus(g_comm->PowerState),g_comm->PowerState, g_comm->KeepOn, g_comm->GetLeftInterval());
    if(g_bt)DebugPrint("Bt              %s: %d %d,left %d\n",PowerStatus(g_bt->PowerState),g_bt->PowerState, g_bt->KeepOn, g_bt->GetLeftInterval());
    if(g_fm)DebugPrint("FM              %s: %d %d,left %d\n",PowerStatus(g_fm->PowerState),g_fm->PowerState, g_fm->KeepOn, g_fm->GetLeftInterval());
    if(g_i2c)DebugPrint("I2C              %s: %d %d,left %d\n",PowerStatus(g_i2c->PowerState),g_i2c->PowerState, g_i2c->KeepOn, g_i2c->GetLeftInterval());
    if(g_display)DebugPrint("LCD             change interval %d:lock %d\n",g_display->ModeChangeInterval,LockScreen);

}
